/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use std::fs::File;
use std::io::{self, BufReader};
use std::path::Path;

use anyhow::{anyhow, Result};
use native_tls::Identity;
use rustls_pemfile::{certs, rsa_private_keys};
use tokio_rustls::rustls::{self, Certificate, PrivateKey};

use crate::utils::read_all;

pub fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
    certs(&mut BufReader::new(File::open(path)?))
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
        .map(|mut certs| certs.drain(..).map(Certificate).collect())
}

pub fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
    rsa_private_keys(&mut BufReader::new(File::open(path)?))
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
        .map(|mut keys| keys.drain(..).map(PrivateKey).collect())
}

pub fn make_server_config(cert_file: &str, key_file: &str) -> Result<rustls::ServerConfig> {
    let (cert_path, key_path) = (Path::new(&cert_file), Path::new(&key_file));
    let certs = load_certs(cert_path)?;
    let mut keys = load_keys(key_path)?;
    let config = rustls::ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(certs, keys.remove(0))
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
    Ok(config)
}

pub fn make_native_identity(cert_file: &str, key_file: &str) -> Result<Identity> {
    let certs = read_all(cert_file.to_string())?;
    let keys = read_all(key_file.to_string())?;
    match Identity::from_pkcs8(certs.as_bytes(), keys.as_bytes()) {
        Ok(v) => { Ok(v) }
        Err(err) => { Err(anyhow!(err.to_string())) }
    }
}